UserLocationAgent: Receive events and accept POST via WebRequestsController.

Show the POST URL on the details page while at it.

The old user_location_updates URLs still work.

This addresses #490.

Akinori MUSHA 10 years ago
parent
commit
f720291b49

+ 9 - 0
app/assets/javascripts/application.js.coffee.erb

@@ -215,3 +215,12 @@ $(document).ready ->
215 215
       showEventCreation()
216 216
     else
217 217
       hideEventCreation()
218
+
219
+  $('.selectable-text').each ->
220
+    $(this).click ->
221
+      range = document.createRange()
222
+      range.setStartBefore(this.firstChild)
223
+      range.setEndAfter(this.lastChild)
224
+      sel = window.getSelection()
225
+      sel.removeAllRanges();
226
+      sel.addRange(range)

+ 1 - 3
app/controllers/user_location_updates_controller.rb

@@ -6,9 +6,7 @@ class UserLocationUpdatesController < ApplicationController
6 6
     if user
7 7
       secret = params[:secret]
8 8
       user.agents.of_type(Agents::UserLocationAgent).find_all {|agent| agent.options[:secret] == secret }.each do |agent|
9
-        agent.create_event :payload => params.except(:controller, :action, :secret, :user_id, :format),
10
-                           :lat => params[:latitude],
11
-                           :lng => params[:longitude]
9
+        agent.trigger_web_request(params.except(:action, :controller, :user_id, :format), request.method_symbol.to_s, request.format.to_s)
12 10
       end
13 11
       render :text => "ok"
14 12
     else

+ 31 - 2
app/models/agents/user_location_agent.rb

@@ -2,7 +2,6 @@ require 'securerandom'
2 2
 
3 3
 module Agents
4 4
   class UserLocationAgent < Agent
5
-    cannot_receive_events!
6 5
     cannot_be_scheduled!
7 6
 
8 7
     description do
@@ -40,5 +39,35 @@ module Agents
40 39
     def validate_options
41 40
       errors.add(:base, "secret is required and must be longer than 4 characters") unless options['secret'].present? && options['secret'].length > 4
42 41
     end
42
+
43
+    def receive(incoming_events)
44
+      incoming_events.each do |event|
45
+        interpolate_with(event) do
46
+          handle_payload event.payload
47
+        end
48
+      end
49
+    end
50
+
51
+    def receive_web_request(params, method, format)
52
+      params = params.symbolize_keys
53
+      if method != 'post'
54
+        return ['Not Found', 404]
55
+      end
56
+      if interpolated['secret'] != params[:secret]
57
+        return ['Not Authorized', 401]
58
+      end
59
+
60
+      handle_payload params.except(:secret)
61
+
62
+      return ['ok', 200]
63
+    end
64
+
65
+    private
66
+
67
+    def handle_payload(payload)
68
+      if payload[:latitude].present? && payload[:longitude].present?
69
+        create_event payload: payload, lat: payload[:latitude].to_f, lng: payload[:longitude].to_f
70
+      end
71
+    end
43 72
   end
44
-end
73
+end

+ 10 - 0
app/views/agents/agent_views/user_location_agent/_show.html.erb

@@ -24,3 +24,13 @@
24 24
     No events found.
25 25
   </p>
26 26
 <% end %>
27
+
28
+<h3>POST URL</h3>
29
+
30
+<p>
31
+  Location data containing <code>latitude</code> and <code>longitude</code> can be posted to this URL:<br/>
32
+
33
+  <ul>
34
+    <li><code class="selectable-text"><%= web_requests_url(user_id: @agent.user_id, agent_id: @agent.id, secret: @agent.options['secret']) %></code></li>
35
+  </ul>
36
+</p>

+ 1 - 1
config/routes.rb

@@ -62,7 +62,7 @@ Huginn::Application.routes.draw do
62 62
 
63 63
   get "/worker_status" => "worker_status#show"
64 64
 
65
-  post "/users/:user_id/update_location/:secret" => "user_location_updates#create"
65
+  post "/users/:user_id/update_location/:secret" => "user_location_updates#create" # legacy
66 66
 
67 67
   match  "/users/:user_id/web_requests/:agent_id/:secret" => "web_requests#handle_request", :as => :web_requests, :via => [:get, :post, :put, :delete]
68 68
   post "/users/:user_id/webhooks/:agent_id/:secret" => "web_requests#handle_request" # legacy

+ 48 - 0
spec/models/agents/user_location_agent_spec.rb

@@ -0,0 +1,48 @@
1
+require 'spec_helper'
2
+
3
+describe Agents::UserLocationAgent do
4
+  before do
5
+    @agent = Agent.build_for_type('Agents::UserLocationAgent', users(:bob), :name => 'something', :options => { :secret => 'my_secret' })
6
+    @agent.save!
7
+  end
8
+
9
+  it 'receives an event' do
10
+    event = Event.new
11
+    event.agent = agents(:bob_weather_agent)
12
+    event.created_at = Time.now
13
+    event.payload = { 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }
14
+
15
+    lambda {
16
+      @agent.receive([event])
17
+    }.should change { @agent.events.count }.by(1)
18
+
19
+    @agent.events.last.payload.should == { 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }
20
+    @agent.events.last.lat.should == 45
21
+    @agent.events.last.lng.should == 123
22
+  end
23
+
24
+  it 'does not accept a web request that is not POST' do
25
+    %w[get put delete patch].each { |method|
26
+      content, status, content_type = @agent.receive_web_request({ 'secret' => 'my_secret' }, method, 'application/json')
27
+      status.should == 404
28
+    }
29
+  end
30
+
31
+  it 'requires a valid secret for a web request' do
32
+    content, status, content_type = @agent.receive_web_request({ 'secret' => 'fake' }, 'post', 'application/json')
33
+    status.should == 401
34
+
35
+    content, status, content_type = @agent.receive_web_request({ 'secret' => 'my_secret' }, 'post', 'application/json')
36
+    status.should == 200
37
+  end
38
+
39
+  it 'creates an event on a web request' do
40
+    lambda {
41
+      @agent.receive_web_request({ 'secret' => 'my_secret', 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }, 'post', 'application/json')
42
+    }.should change { @agent.events.count }.by(1)
43
+
44
+    @agent.events.last.payload.should == { 'longitude' => 123, 'latitude' => 45, 'something' => 'else' }
45
+    @agent.events.last.lat.should == 45
46
+    @agent.events.last.lng.should == 123
47
+  end
48
+end